#include "stdafx.h"
#include "Thread.h"
#include "WindowsUtility.h"
#include "SendMessageError.h"

#include <RoomFW/IActiveObject.h>

////////////////////////////////////////////////////////////////////////
// BEGIN MSDN CODE
#define MS_VC_EXCEPTION 0x406D1388

typedef struct tagTHREADNAME_INFO
{
   DWORD dwType; // Must be 0x1000.
   LPCSTR szName; // Pointer to name (in user addr space).
   DWORD dwThreadID; // Thread ID (-1=caller thread).
   DWORD dwFlags; // Reserved for future use, must be zero.
} THREADNAME_INFO;

void SetThreadName( DWORD dwThreadID, LPCSTR szThreadName)
{
   THREADNAME_INFO info;
   info.dwType = 0x1000;
   info.szName = szThreadName;
   info.dwThreadID = dwThreadID;
   info.dwFlags = 0;

   __try
   {
	   ::RaiseException(MS_VC_EXCEPTION, 0, sizeof(info)/sizeof(DWORD), reinterpret_cast<const ULONG_PTR*>(&info));
   }
   __except(EXCEPTION_CONTINUE_EXECUTION)
   {
   }
}
// END MSDN CODE
////////////////////////////////////////////////////////////////////////

namespace RoomFW {

Thread::Thread(void) :
	handle_(0),
	running_(),
	stopped_(),
	isErrored_(false),
	errorMessage_(),
	errorGuard_()
{
	// "Safe" constructor.  Nothing to fail.
}

Thread::~Thread(void)
{
	// We can't call signalStop() here, because derived class is already destructed,
	// but the derived class better have stopped before we get here.
	ASSERT(!this->isRunning());
}

bool Thread::start(uint32_t timeout, int priority)
{
	bool retVal = true;
	try
	{
		// Return false if already running.
		if (this->isRunning())
		{
			throw "Thread::start() - already running";
		}

		// Create events here since we can return failure.
		if (!running_.create(true, false)) // Manual reset, Initially unsignaled.
		{
			throw "Thread::start() failed to create running event";
		}
		if (!stopped_.create(true, false)) // Manual reset, Initially signaled.
		{
			throw "Thread::start() failed to create stopped event";
		}
		if (!this->initializeObject()) // do derived init
		{
			throw "Thread::start() - initializeObject() failed";
		}
		if (!stopped_.reset()) // Not stopped anymore.
		{
			throw "Thread::start() - failed to reset stopped event";
		}
		// Clear errors.  Not running, so no guard.
		isErrored_ = false;
		errorMessage_.clear();

		// Start the thread.
		uintptr_t threadId = ::_beginthread(ThreadProc, 0, this);
		SHOW_ERRNO((1L != threadId), "Thread::start", "::_beginthread");
		if (1L == threadId)
		{
			VERIFY(stopped_.set()); // failed to start
			throw "Thread::start() - ::_beginthread() failed";
		}
		else
		{
			// Save thread handle.
			handle_ = reinterpret_cast<HANDLE>(threadId);

			// Set thread priority if necessary.
			if (THREAD_PRIORITY_NORMAL != priority)
			{
				BOOL tps = ::SetThreadPriority(handle_, priority);
				SHOW_LAST_ERROR(tps, "Thread::start", "::SetThreadPriority");
				if (!tps)
				{
					throw "Thread::start() - ::SetThreadPriority() failed";
				}
			}
			// Wait for running.
			this->isRunning(timeout); // wait, ignore return.
		}
	}
	catch (const char* e)
	{
		this->setError(e);
		retVal = false;
	}
	catch(...)
	{
		this->setError("Thread::start() - Unhandled Exception");
		retVal = false;
	}
	return retVal;
}

bool Thread::stop(uint32_t timeout)
{
	// Just return true if already stopped.
	bool retVal = !isRunning();
	if (!retVal)
	{
		signalStop();
		retVal = this->wait(timeout);
	}
	return retVal;
}

bool Thread::wait(uint32_t timeout)
{
	// Return true if not running or wait for stop event succeeds.  Doesn't cause it to stop.
	return (!this->isRunning() || stopped_.wait(timeout));
}

bool Thread::isRunning(uint32_t timeout)
{
	// Not running if not initialized.  Can't wait on null handles.
	bool retVal = ((0 != running_) && (0 != stopped_));
	if (retVal)
	{
		// Wait for running or stopped event.  Only return true if running.
		const HANDLE handles[] = {running_, stopped_};
		const size_t count = sizeof(handles) / sizeof(HANDLE);
		DWORD waitResult = ::WaitForMultipleObjects(count, handles, false, timeout);
		SHOW_LAST_ERROR((WAIT_FAILED != waitResult), "Thread::isRunning", "::WaitForMultipleObjects");
		retVal = (WAIT_OBJECT_0 == waitResult);
	}
	return retVal;
}

int Thread::getThreadPriority()
{
	int retVal = THREAD_PRIORITY_ERROR_RETURN;
	if (this->isRunning())
	{
		retVal = ::GetThreadPriority(handle_);
	}
	return retVal;
}


bool Thread::isErrored()
{
	bool retVal = false;
	{CriticalSectionGuard g(errorGuard_);
		retVal = isErrored_;
	}
	return retVal;
}

std::string Thread::errorMessage()
{
	std::string retVal;
	{CriticalSectionGuard g(errorGuard_);
		retVal = errorMessage_;
	}
	return retVal;
}

ErrorHandling::IErrorSP Thread::getError()
{
	ErrorHandling::IErrorSP retVal;
	{CriticalSectionGuard g(errorGuard_);
		retVal = lastError_;
	}
	return retVal;
}

const char* Thread::getThreadName() const
{
	return "RoomFW::Thread";
}

void Thread::ThreadProc(void* _this)
{
	Thread *thisThread=static_cast<Thread*>(_this);
	try
	{
		static_cast<Thread*>(_this)->run();
	}
	catch (...)
	{
		IActiveObject *thisAO = dynamic_cast<IActiveObject *>(thisThread);
		const char *thisName=NULL;
		if( thisAO ) {
			thisName = thisAO->getObjectName();
		}else{
			thisName = thisThread->getThreadName();
		}
		G_LOG_1(LV_SYSTEM, "Thread %s Exit when exception.\n", thisName);
		// Last fail-safe.  Don't do anything!
	}
	::_endthread();
}

void Thread::run(void)
{
	Thread *thisThread=static_cast<Thread*>(this);
	IActiveObject *thisAO = dynamic_cast<IActiveObject *>(thisThread);
	const char *thisName=NULL;
	if( thisAO ) {
		thisName = thisAO->getObjectName();
	}else{
		thisName = thisThread->getThreadName();
	}
	try
	{
		::SetThreadName(-1, this->getThreadName());
		if (this->initializeThread())
		{
			if (running_.set())
			{
				this->onStart();
				this->main();
				this->onStop();
			}
			this->finalize();

			// Prefer to only clear if set succeeded, but need to
			// finalize first and no harm if it fails.
			running_.reset();
		}
		stopped_.set();
	}
	catch(ErrorHandling::IError& e)
	{
		{CriticalSectionGuard g(errorGuard_);
			lastError_ = e.clone();
		}
		this->setError(e.what());
		G_LOG_2(LV_ERROR, "Thread [%s] caught ErrorHandling::IError %s", thisName, e.what());
	}
	catch(std::runtime_error& e)
	{
		this->setError(e.what());
		G_LOG_2(LV_ERROR, "Thread [%s] caught std::runtime_error %s", thisName, e.what());
	}
	catch(std::exception& e)
	{
		this->setError(e.what());
		G_LOG_2(LV_ERROR, "Thread [%s] caught std::exception %s", thisName, e.what());
	}
	catch(...)
	{
		this->setError("Unhandled Exception");
		G_LOG_1(LV_ERROR, "Thread caught Unhandled Exception [%s].", thisName);
	}
}

void Thread::setError(const char* errorMessage)
{
	{CriticalSectionGuard g(errorGuard_);
		isErrored_ = true;
		errorMessage_ = errorMessage;
	}
	running_.reset();
	stopped_.set();
}

void EventThread::main(void)
{
	while (this->waitEvent() && this->handleEvent())
		; // Loop until error or shutdown.
}

}
